package com.zx.cloud.common.filter.limit;

import java.util.HashMap;
import java.util.Map;

public class LimiterStatsService {

	
	private Map<String, LimiterStats> limiterMap = new HashMap<String, LimiterStats>();
	
	private static LimiterStatsService limiterStatsService;
	
	private static Integer limitDefault=1;
	
	
	private static LimiterCallback limiterCallbackDefault=new LimiterCallback() {
		
		@Override
		public void noexecute(LimiterContext limiterContext) {
			
		}
		
		@Override
		public void execute(LimiterContext limiterContext) {
			
		}
	};
	
	public interface LimiterCallback{
		
		void noexecute(LimiterContext limiterContext);
		
		void execute(LimiterContext limiterContext);
		
	}
	
	public static class LimiterStats {

		private long timestamp;
		private String key;
		private int requests;

		public long getTimestamp() {
			return timestamp;
		}

		public String getKey() {
			return key;
		}

		public int getRequests() {
			return requests;
		}

		public LimiterStats setTimestamp(long timestamp) {
			this.timestamp = timestamp;
			return this;
		}

		public LimiterStats setKey(String key) {
			this.key = key;
			return this;
		}

		public LimiterStats setRequests(int requests) {
			this.requests = requests;
			return this;
		}

	}
	
	public static class LimiterContext{
		
		private Integer limit;
		private LimiterStats stats;
		
		public Integer getLimit() {
			return limit;
		}
		public void setLimit(Integer limit) {
			this.limit = limit;
		}
		public LimiterStats getStats() {
			return stats;
		}
		public void setStats(LimiterStats stats) {
			this.stats = stats;
		}
		
	}
	
	public static LimiterStatsService getInstance(){
		synchronized (LimiterStatsService.class) {
			if(limiterStatsService==null){
				limiterStatsService=new LimiterStatsService();
			}
		}
		return limiterStatsService;
	}
	
	/**
	 * 每秒钟限制执行次数
	 * @param key
	 * @param limit 次数
	 * @param seconds 几秒钟以内
	 * @param limiterCallback 执行回调
	 */
	public void execute(String key,Integer limit,Integer seconds,LimiterCallback limiterCallback){
		if(limiterCallback==null) limiterCallback=limiterCallbackDefault;
		if(limit==null) limit=limitDefault;
		final long timestamp =(System.currentTimeMillis() / 1000l) * ((seconds==null||seconds<0)?1*1000l:seconds*1000l);
		LimiterStats stats = limiterMap.get(key);
		if (stats == null || (stats.getTimestamp()) < timestamp) {
			stats = new LimiterStats().setTimestamp(timestamp).setKey(key).setRequests(0);
			limiterMap.put(key, stats);
		}
		LimiterContext limiterContext=new LimiterContext();
		limiterContext.setLimit(stats.getRequests());
		limiterContext.setStats(stats);
		if (stats.getRequests() >= limit) {
			limiterCallback.noexecute(limiterContext);
		} else {
			stats.setRequests(stats.getRequests() + 1);
			limiterMap.put(stats.getKey(), stats);
			limiterCallback.execute(limiterContext);
		}
	}

}